package com.interview.jvm;

public class Dervied extends Base {
	private String name = "dervied";

	Dervied() {
		tellName();
		printName();
	}

	public void tellName() {
		System.out.println("Dervied tell name:" + name);
	}

	public void printName() {
		System.out.println("Dervied print name:" + name);
	}

	public static void main(String[] args) {
		new Dervied();
	}

}

class Base {
	private String name = "base";

	Base() {
		tellName();
		printName();
	}

	public void tellName() {
		System.out.println("Base tell name:" + name);
	}

	public void printName() {
		System.out.println("Base print name:" + name);
	}
}

// Dervied tell name:null
// Dervied print name:null
// Dervied tell name:dervied
// Dervied print name:dervied

/**
 * 1，首先先说一下父类与子类方法覆写（overrider）相关的概念，覆写在java中主要是通过方法表来完成，
 * java中每个类型（Class）中都存在一个方法表，其中存放java类型的实例方法（public/protected），
 * static方法属于静态方法，和类型相关
 * ，不属于javad实例方法。private和default属于私有方法，private/default修饰的方法不进入类型的方法表。
 *
 * 2，接下来说一下<clinit>和<init>方法，其中<clinit>称为类初始化方法，<init>称为对象实例化方法，该问题就与<init>
 * 方法息息相关。 <clinit>方法:
 * Java在进行对象创建时首先进行类型加载，如果Class类型存在父类型，则需要先加载父类完成以后再加载子类型。并且对static变量进行初始化操作，
 * 对static变量或者static代码块初始化的逻辑就封装在
 * <clinit>方法中。Java类型初始化过程中对static变量的初始化操作依赖与对static变量的赋值语句的前后关系，
 * static语句块与static变量声明存在位置关系，java编译器与static变量的赋值位置有关。
 *
 * <init>方法:Java对象在进行实例化时，首先会进行父类的实例化操作，然后再进行子类的实例化操作。该部分操作封装在<init>方法中，并且子类的<
 * init>方法中会首先对父类<init>方法的调用。
 * Java对象实例化过程中对实例域的初始化赋值操作全部在<init>方法中进行，<init>方法显式的调用父类的
 * <init>方法，实例域的声明语句以及实例初始化语句块存在位置关系，<init>方法以构造方法作为结束。
 * --------------------------
 * ----------------------------------------------------
 * --------------------------------------
 *
 * 接下来回到这道题上来，启动java虚拟机： 第一步：加载应用用到的类，加载顺序为Base-->Dervied，这里涉及到<clinit>方法的调用，
 * 但是当前类型中没有static域或者是static{}，所以<clinit>方法不再讨论。 第二步：对象实例化操作，首先我们new
 * Dervied();，这样就触发对Dervied
 * .<init>的调用，但是根据以上知识（“并且子类的<init>方法中会首先对父类<init>方法的调用”）我们可以知道，
 * Dervied.<init>首先会调用到Base
 * .<init>方法，所以现在我们调用的方法是Base.<init>，Base.<init>方法中，首先是对name域
 * （父类Base）进行初始化，然后调用tellName()方法，
 * 因为子类以及覆写了tellName()方法，所以tellName方法实际调用为Dervied
 * .tellName()方法，tellName方法要打印name域（子类Dervied）的值，
 * 但是当前Dervied对象中的name域还没有被初始化，所以打印出来的值为null。printName()方法执行与tellName()方法一致。
 * 第三步：Base.<init>方法返回到Dervied.<init>方法中，紧接着对name域（子类Dervied）进行初始化操作，
 * 然后调用子类Dervied的tellName方法和printName方法， name域（子类Dervied）已经初始化完成，所以能正确打印出来。
 * ------
 * ------------------------------------------------------------------------
 * --------------------------------------
 */
